<script setup lang="ts">
import {ref, onMounted, nextTick, watch, reactive} from 'vue'
import {invoke} from "@tauri-apps/api/core";
import {bind, send, unbind} from "@kuyoonjo/tauri-plugin-udp";
import {listen, UnlistenFn} from "@tauri-apps/api/event";
import {ElMessage} from "element-plus";
import LineCard from "../Tool/line-card.vue";
import {save} from "@tauri-apps/plugin-dialog";
import {write_file} from "../../lib/database.ts";

interface MessageInterface {
    data: string
    mode: boolean
    host: string
}

const scrollbarRef = ref()
const content = ref('我爱你')
const message = ref<MessageInterface[]>([])

interface payload {
    id: string
    addr: string
    data: []
}

const network = reactive({
    ipAddress: '',
    port: 8888,
    id: 'udp-id',
    remoteHostList: [],
    remoteHost: '',
    sendHost: '',
    rx: 0,
    tx: 0
})

const config = reactive({
    rxColor: '#409EFF',
    txColor: '#67C23A',
    rxSize: 18,
    txSize: 18,
    sendHex: 'Ascii',
    receiveHex: 'Ascii',
    inputSize: 18,
})
const tempConfig = reactive({...config})
// true为关闭，false为打开
const mode = ref(false)
const drawer = ref(false)
const visible = ref(false)

let unListen: UnlistenFn = null

onMounted(async () => {
    network.ipAddress = await invoke('get_ip')
    network.remoteHost = network.ipAddress + ':' + network.port
    network.sendHost = network.ipAddress + ':' + network.port
    network.remoteHostList.push(network.ipAddress + ':' + network.port)
    scrollToBottom()
})

const scrollToBottom = () => {
    nextTick(() => {
        const scrollbar = scrollbarRef.value?.wrapRef
        if (scrollbar) {
            scrollbar.scrollTop = scrollbar.scrollHeight
        }
    })
}

watch(message, scrollToBottom, {deep: true})

const handleOpenServer = async () => {
    if (mode.value) {
        unListen()
        await unbind(network.id)
        ElMessage.success('关闭成功')
        mode.value = false
        return
    }
    await bind(network.id, network.ipAddress + ':' + network.port)
    mode.value = true
    ElMessage.success('打开成功')
    unListen = await listen("plugin://udp", (data) => {
        if (network.remoteHostList.indexOf((data.payload as payload).addr) === -1) {
            network.remoteHostList.push((data.payload as payload).addr)
        }
        // 更改接收数量的设置
        network.rx += (data.payload as payload).data.length
        if (config.receiveHex === 'Hex') {
            message.value.push({
                data: (data.payload as payload).data.map((item: number) =>
                    item.toString(16).toUpperCase()).join(' '),
                mode: true,
                host: (data.payload as payload).addr
            })
        } else {
            // 将十进制数组转换为Uint8Array
            const bytes = new Uint8Array((data.payload as payload).data);
            // 使用TextDecoder解码UTF-8数据
            const decoder = new TextDecoder('utf-8');
            const text = decoder.decode(bytes);
            message.value.push({
                data: text,
                mode: true,
                host: (data.payload as payload).addr
            })
        }
    })
}

const handleSendClick = async () => {
    if (!mode.value) {
        ElMessage.warning('请先打开服务器')
        return
    }
    if (content.value === '') {
        ElMessage.warning('请输入内容')
        return
    }
    if (network.sendHost === '') {
        ElMessage.warning('请选择远程主机')
        return
    }

    if (config.sendHex === 'Hex') {
        const data = (content.value as string).split(' ').map(item => parseInt(item, 16))
        network.tx += data.length
        message.value.push({
            data: content.value,
            mode: false,
            host: network.sendHost
        })
        await send(network.id, network.sendHost, data)
    } else {
        const data = (new TextEncoder()).encode(content.value)
        network.tx += data.length
        message.value.push({
            data: content.value,
            mode: false,
            host: network.sendHost
        })
        await send(network.id, network.sendHost, content.value)
    }
    // 发送成功后，将IP地址添加到远程主机列表中
    if (network.remoteHostList.indexOf(network.sendHost) === -1) {
        network.remoteHostList.push(network.sendHost)
        network.remoteHost = network.sendHost
    }
}

const handleConfigClick = async () => {
    if (config.sendHex !== tempConfig.sendHex) {
        Object.assign(config, tempConfig);
        // 如果突然更改成HEX模式发送，将内容转换为HEX
        if (config.sendHex === 'Hex') {
            const data = (new TextEncoder()).encode(content.value)
            content.value = Array.from(data).map(byte => byte.toString(16).toUpperCase().padStart(2, '0')).join(' ')
        } else {
            // 如果突然更改成ASCII模式发送，将内容转换为ASCII
            const data = content.value.split(' ').map(byte => parseInt(byte, 16))
            content.value = (new TextDecoder()).decode(new Uint8Array(data))
        }
    }
    Object.assign(config, tempConfig);
    drawer.value = false
}

const filterHexInput = (e: InputEvent) => {
    if (config.sendHex === 'Hex') {
        const target = e.target as HTMLTextAreaElement;
        const value = target.value;
        const hexValue = value.replace(/[^0-9A-Fa-f\s]/g, '');
        if (value !== hexValue) {
            // 恢复之前的合法值
            target.value = hexValue;
            content.value = hexValue;
            // 提示用户输入了非十六进制字符
            visible.value = true;
            setTimeout(() => {
                visible.value = false;
            }, 2000)
        }
    }
}

const exportRecord = async () => {
    if (message.value.length === 0) {
        ElMessage.warning('暂无记录')
        return
    }
    const filepath = await save({
        filters: [{name: 'Text Files', extensions: ['txt']}],
        title: '导出记录',
        defaultPath: 'udp.txt'
    })
    if (filepath === null) {
        ElMessage.error('未选择保存文件')
        return
    }
    // 构建字符串
    const data = message.value.map(item => {
        if (item.mode) {
            return `Receive From:[${item.host}]\n${item.data}\n`
        } else {
            return `Send To:[${item.host}]\n${item.data}\n`
        }
    }).join('')
    await write_file(filepath, data)
    ElMessage.success('导出成功')
}

</script>

<template>
    <div style="height: 50px">
        <el-row>
            <el-col :span="2">
                <el-text style="font-size: 30px; font-weight: bold">UDP</el-text>
            </el-col>
            <el-col :span="22" style="display: flex; justify-content: end; height: 50px; align-items: center;">
                <el-button type="primary" @click="message = []">清空</el-button>
                <el-button type="warning" @click="exportRecord">导出</el-button>
                <el-button type="success" @click="drawer = true">更多配置</el-button>
            </el-col>
        </el-row>
    </div>
    <el-card style="height:  calc(60% - 50px)" body-style="height: calc(100% - 40px)">
        <el-scrollbar ref="scrollbarRef" style="height: 100%; margin-top: 5px;">
            <line-card
                v-for="(item, index) in message"
                :key="index"
                :rx-color="config.rxColor"
                :tx-color="config.txColor"
                :rx-size="config.rxSize"
                :tx-size="config.txSize"
                :data="item.data"
                :mode="item.mode"
                :host="item.host"/>
        </el-scrollbar>
    </el-card>
    <el-card style="height: 10%; margin-top: 5px;">
        <el-row>
            <el-col :span="20" style="display: flex; justify-content: flex-start;">
                <div class="network-config">
                    <span style="margin-right: 5px">地址</span>
                    <el-input
                        v-model="network.ipAddress"
                        placeholder="地址"
                        size="default"
                        :disabled="mode"
                        style="width: 135px"
                    />
                </div>
                <div class="network-config">
                    <span style="margin-right: 5px">端口</span>
                    <el-input
                        v-model="network.port"
                        placeholder="端口"
                        size="default"
                        :disabled="mode"
                        style="width: 70px"
                    />
                </div>
                <div class="network-config">
                    <span style="margin-right: 5px">远程主机列表</span>
                    <el-select
                        v-model="network.remoteHost"
                        placeholder="远程主机"
                        size="default"
                        style="width: 190px"
                    >
                        <el-option
                            v-for="item in network.remoteHostList"
                            :key="item"
                            :label="item"
                            :value="item"
                        />
                    </el-select>
                </div>
                <div class="network-config">
                    <span style="margin-right: 5px">远程主机</span>
                    <el-input
                        v-model="network.sendHost"
                        placeholder="远程主机"
                        size="default"
                        style="width: 190px"
                    />
                </div>
                <div class="network-config config-last">
                    <span style="margin-right: 5px">RX</span>
                    <el-text>{{ network.rx }}</el-text>
                    <span style="margin-right: 5px; margin-left: 5px;">TX</span>
                    <el-text>{{ network.tx }}</el-text>
                </div>
            </el-col>
            <el-col :span="4" style="height: 100%; display: flex; flex-direction: row; justify-content: space-between; align-items: center">
                <el-button type="primary" style="width: 40%" size="default" @click="handleOpenServer" v-if="!mode">
                    开启
                </el-button>
                <el-button type="success" style="width: 40%" size="default" @click="handleOpenServer" v-else>
                    关闭
                </el-button>
                <el-button type="primary" style="width: 40%" size="default" @click="network.rx = 0; network.tx = 0">
                    清零
                </el-button>
            </el-col>
        </el-row>
    </el-card>
    <el-card style="height: calc(30% - 20px); margin-top: 5px;" body-style="height: calc(100% - 40px)">
        <el-row :gutter="5" style="width: 100%; height: 100%">
            <el-col :span="22" style="width: 100%; height: 100%; max-width: 100%; max-height: 100%">
                <el-popover :visible="visible" placement="top" :width="180" type="warning">
                    <p>HEX模式下，只允许输入16进制数</p>
                    <template #reference>
                        <textarea
                            class="input__inner"
                            v-model="content"
                            @input="filterHexInput"
                        />
                    </template>
                </el-popover>
            </el-col>
            <el-col :span="2" style="height: 100%; display: flex; flex-direction: column; justify-content: space-between; align-items: center">
                <el-button @click="handleSendClick"
                           type="primary" size="default" style="width: 80%; margin-left: 22px;">
                    发送
                </el-button>
                <el-button @click="content = ''"
                           type="primary" size="default" style="width: 80%; margin-left: 22px;">
                    清空
                </el-button>
            </el-col>
        </el-row>
    </el-card>
    <el-drawer v-model="drawer"
               title="更多配置"
               :close-on-click-modal="false"
               :with-header="true">
        <el-form
            label-position="right"
            label-width="auto"
        >
            <el-form-item label="接收配置" label-position="right" class="form-item">
                <el-row style="width: 100%">
                    <el-col :span="12">
                        <span style="margin-right: 5px">颜色</span>
                        <el-color-picker
                            v-model="tempConfig.rxColor"
                            size="default"
                        />
                    </el-col>
                    <el-col :span="12">
                        <span style="margin-right: 5px">字体大小</span>
                        <el-select
                            v-model="tempConfig.rxSize"
                            placeholder="字体大小"
                            style="width: 50%"
                            size="default">
                            <el-option
                                v-for="item in [12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50]"
                                :key="item"
                                :label="item"
                                :value="item"/>
                        </el-select>
                    </el-col>
                </el-row>
            </el-form-item>
            <el-form-item label="发送配置" label-position="right" class="form-item">
                <el-row style="width: 100%">
                    <el-col :span="12">
                        <span style="margin-right: 5px">颜色</span>
                        <el-color-picker
                            v-model="tempConfig.txColor"
                            size="default"
                        />
                    </el-col>
                    <el-col :span="12">
                        <span style="margin-right: 5px">字体大小</span>
                        <el-select
                            v-model="tempConfig.txSize"
                            placeholder="字体大小"
                            style="width: 50%"
                            size="default">
                            <el-option
                                v-for="item in [12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50]"
                                :key="item"
                                :label="item"
                                :value="item"/>
                        </el-select>
                    </el-col>
                </el-row>
            </el-form-item>
            <el-form-item label="发送形式" label-position="right" class="form-item">
                <el-radio-group v-model="tempConfig.sendHex" style="width: 100%; display: flex; justify-content: space-around">
                    <el-radio value="Hex">16进制</el-radio>
                    <el-radio value="Ascii">字符串</el-radio>
                </el-radio-group>
            </el-form-item>
            <el-form-item label="接收形式" label-position="right" class="form-item">
                <el-radio-group v-model="tempConfig.receiveHex" style="width: 100%; display: flex; justify-content: space-around">
                    <el-radio value="Hex">16进制</el-radio>
                    <el-radio value="Ascii">字符串</el-radio>
                </el-radio-group>
            </el-form-item>
            <el-form-item label="输入框大小" label-position="right" class="form-item">
                <el-select
                    v-model="tempConfig.inputSize"
                    placeholder="输入框大小"
                    size="default">
                    <el-option
                        v-for="item in [12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50]"
                        :key="item"
                        :label="item"
                        :value="item"/>
                </el-select>
            </el-form-item>
            <el-form-item style="text-align: center;">
                <div style="width: 100%; display: flex; justify-content: center">
                    <el-button type="primary" @click="handleConfigClick">
                        应用
                    </el-button>
                    <el-button type="warning" @click="drawer = false; ">取消</el-button>
                </div>
            </el-form-item>
        </el-form>
    </el-drawer>
</template>
<style scoped lang="css">
.network-config {
    display: flex;
    align-items: center;
    margin-right: 15px;
}

.config-last {
    margin-right: 0;
}

.input__inner {
    height: 100%;
    width: 100%;
    resize: none;
    overflow-y: auto;
    font-family: inherit;
    font-size: var(--el-font-size-base);
    padding: 5px 12px;
    color: var(--el-text-color-regular);
    background-color: var(--el-input-bg-color, var(--el-fill-color-blank));
    outline: none;
    box-shadow: 0 0 0 1px var(--el-input-border-color, var(--el-border-color)) inset;
    border-radius: var(--el-input-border-radius, var(--el-border-radius-base));
    transition: var(--el-transition-box-shadow);
    border: none;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}

.input__inner:hover {
    box-shadow: 0 0 0 1px var(--el-border-color-hover) inset;
}

.input__inner:focus {
    outline: none;
    box-shadow: 0 0 0 1px var(--el-color-primary) inset;
}

textarea:focus-visible {
    outline-offset: 0;
}
</style>